package com.own.stu.apm.agent.core.plugin;

import com.own.stu.apm.agent.core.plugin.interceptor.ConstructorMethodsInterceptorPoint;
import com.own.stu.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptorPoint;
import com.own.stu.apm.agent.core.plugin.interceptor.StaticMethodsInterceptorPoint;
import com.own.stu.apm.agent.core.plugin.match.ClassMatch;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;

/**
 * 是所有插件的顶级父类
 */
@Slf4j
public abstract class AbstractClassEnhencePluginDefine {

    /*
    新属性名称
     */
    public static final String CONTEXT_ATTR_NAME = " $EnhencedclassField_ws";


    /**
     * 获取当前插件要增强的类
     */
    protected abstract ClassMatch enhanceClass();

    /*
    获取实例方法的拦截点
     */
    protected abstract InstanceMethodsInterceptorPoint[] getInstanceMethodsInterceptorPoint();

    /*
    获取构造方法的拦截点
     */
    protected abstract ConstructorMethodsInterceptorPoint[] getConstructorMethodsInterceptorPoint();

    /*
    获取静态方法的拦截点
     */
    protected abstract StaticMethodsInterceptorPoint[] getStaticMethodsInterceptorPoint();

    public DynamicType.Builder<?> define(TypeDescription typeDescription, DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext enhanceContext) {
        // com.own.stu.apm.plugins.springmvc.RestControllerInstrumentation
        String pluginDefineClassName = this.getClass().getName();
        // com.own.stu.app.web.BasicController
        String typeName = typeDescription.getTypeName();
        log.debug("begin use {} hence {}", pluginDefineClassName, typeName);
        DynamicType.Builder<?> newBuilder = this.enhance(typeDescription, builder, classLoader, enhanceContext);
        enhanceContext.initializationStageCompleted();
        log.debug("end use {} hence {}", pluginDefineClassName, typeName);
        return newBuilder;
    }

    private DynamicType.Builder<?> enhance(TypeDescription typeDescription, DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext enhanceContext) {
        builder = this.enhanceClass(typeDescription, builder, classLoader);
        builder = this.enhanceInstance(typeDescription, builder, classLoader, enhanceContext);
        return builder;
    }

    // 增强实例方法和构造方法
    protected abstract DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription, DynamicType.Builder<?> builder, ClassLoader classLoader, EnhanceContext enhanceContext);

    // 增强静态方法
    protected abstract DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> builder, ClassLoader classLoader);
}
